﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Linq;
using Styx;
using Styx.Helpers;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Profiles;
using Styx.CommonBot.POI;
using Styx.CommonBot.AreaManagement;
using Styx.MemoryManagement;
using Styx.Pathing;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals.World;
using Styx.Plugins;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;




namespace BuddyManager
{
    public partial class BuddyManager : HBPlugin
    {
        /*
         * Project:  BuddyManager
         * Main Use:  Switch Bot-Base & Profile & Zone
         * Scheduling and Randomization
         * 
         * 
         * Author:  No1KnowsY - http://www.thebuddyforum.com/members/11607-no1knowsy.html
         * Last updated: 24 OCT 2012
         * 
         * Live Thread: http://www.thebuddyforum.com/honorbuddy-forum/plugins/uncataloged/69991-plugin-buddymanager-schedule-your-game-tasks-profiles-zones-botbases.html
         * Old Thread(Archived): http://www.thebuddyforum.com/archives/38456-plugin-buddymanager-botbase-profile-zone-changer-now-w-scheduling.html
         * 
         * Enjoy >:D
         */
        public static string InternalName { get { return "BuddyManager"; } }
        public override string Name { get { return BuddyManager.InternalName; } }
        public override string Author { get { return "No1KnowsY"; } }
        public override Version Version { get { return new Version(2, 2, 26); } }
        public LocalPlayer Me { get { return StyxWoW.Me; } }
        public override string ButtonText { get { return BuddyManager.InternalName; } }
        public static string STATUS = "";
        public static DateTime _TotalStartTime;
        public static DateTime _BaseStartTime;
        public Stopwatch TimeToAlertTimer = new Stopwatch();
        public bool MovementRunning = false;
        public bool NeedToRepairMailSell = false;
        public bool ForcedSRM = false;
        public bool HitLevel = false;
        public bool StartTimeSet = false;
        public bool AfterHearth = false;
        public bool NeedHearth = false;
        public bool SitAtHearth = false;
        public bool IsNewZone = false;
        public bool LoadedFirst = false;
        public bool NeedToFly = false;
        public bool DidJustRestart = false;
        public bool DidUseHearth = false;
        public bool EXITNOW = false;
        public bool DidUsePortal = false;
        public bool SwappingToNewProfileSkipStartupResets = false;
        public bool GB2_StoredSettings = false;
        public bool harvestHerbs, harvestOres;
        public int _InternalNodeCount = 0;
        public int LastProfileIndex;

        public override bool WantButton { get { return true; } }

        private Form _configForm;
        public override void OnButtonPress()
        {
            if (_configForm == null || _configForm.IsDisposed || _configForm.Disposing)
                _configForm = new NewUI();
                _configForm.FormClosed += _configForm_FormClosed;
                Log("BuddyManager Config Opened!");
                _configForm.Show();
        }
        private void _configForm_FormClosed(object sender, EventArgs eve)
        { 
            Log("BuddyManager Config Closed!");
            Log("Listing All Tasks!");
            LoadSettings();
            foreach (var x in TaskList)
                x.ToLog();
        }

        public override void Initialize()
        {
            Styx.CommonBot.BotEvents.OnBotStarted += BotEvents_OnBotStarted;
            //Styx.BotEvents.OnBotStop += BotEvents_OnBotStop;
            uSettings.initSettings();
            LoadSettings();
            Log(string.Format("Initialized ~ Version: {0}.{1} - Build: {2}", Version.Major, Version.Minor, Version.Build));

            if (Me.Level < 80)
            {
                Log("Your toon is not level 80+."); 
                Log("Depending on what your settings are I CANNOT guarantee that it will work.");
                Log("For more information see the second post on The BuddyManager's thread on TheBuddyForum.");
            }
        }

        public override void Dispose()
        {
            Styx.CommonBot.BotEvents.OnBotStarted -= BotEvents_OnBotStarted;
        }

        private void BotEvents_OnBotStarted(object _object)
        {
            LoadSettings();
            if (!StartTimeSet) { _TotalStartTime = DateTime.Now; StartTimeSet = true; }

            if (BotManager.Current.Name == "Gatherbuddy2")
            {
                _InternalNodeCount += GB2FullNodesCollection();
            }
            else
            {
                _InternalNodeCount = 0;
            }
            //Get back to this
            if (SwappingToNewProfileSkipStartupResets)
            {
                SwappingToNewProfileSkipStartupResets = false;
            }
            else
            {
                _BaseStartTime = DateTime.Now;
            }
            //Log("Loaded setting (Bot Started).");
        }

        private void BotEvents_OnBotStop(object _object)
        {
            TotalRunningTime();
            TotalBaseTime();
        }

        #region Settings Variables

        //NEW TASK SETUP!
        public static Int32 CurrentTaskIndex = 0, LastTaskIndex = -1, CurrentProfileIndex = 0;
        public static List<TaskStruct> TaskList = new List<TaskStruct>();

        public bool IsLastProfile()
        {
            if ((CurrentProfileIndex + 1) >= TaskList[CurrentTaskIndex].ProfileList.Count)
                return true;
            else
                return false;
        }

        public class TaskStruct
        {
            public string BotBase, Zone;
            public Int32 SwitchInt;
            public List<string> ProfileList = new List<string>();
            public string SwitchOn;

            public void ToLog()
            {
                if (TaskList.Count > 0)
                {
                    Log(string.Format("BotBase: {0}", BotBase));
                    Log(string.Format("Zone: {0}", Zone));
                    Log(string.Format("Switch On: {0}", SwitchOn));
                    Log(string.Format("Switch Int: {0}", SwitchInt));
                    foreach (var s in ProfileList)
                        Log(string.Format("Profiles: {0}", s));
                }
                else
                    Log("NO TASKS FOUND!  OH F*CK!");
            }


            public static XElement ToXml(TaskStruct task)
            {
                return new XElement("Task",
                    new XElement("BotBase", task.BotBase),
                    new XElement("Zone", task.Zone),
                    new XElement("SwitchOn", task.SwitchOn),
                    new XElement("SwitchInt", task.SwitchInt.ToString()),
                    new XElement("Profiles",
                        from i in task.ProfileList
                        select i.ToXml("Profile"))
                    );
            }
        }

        public static UserSet uSettings = new UserSet();
        public struct UserSet
        {
            public bool LogOutAfter, Vendor, Mail, ForceNext, Randomize, shortBreak;
            public int TotalHr, TotalMin, NumOfTasks, TasksCompleted;
            public WoWUnit CachedMe;

            public void initSettings()
            {
                LogOutAfter = true; shortBreak = false;
                Vendor = false; Mail = false; ForceNext = false; Randomize = false;
                TotalHr = 0; TotalMin = 0; NumOfTasks = 0; TasksCompleted = 0;
                CachedMe = StyxWoW.Me;
            }
        }

        public _ProfileManager _Manager = new _ProfileManager(null);
        public struct _ProfileManager
        {

            public Dictionary<uint, string> ZonePairHorde, ZonePairAlly, ZoneIdDict;
            public int PandariaMapId;


            public _ProfileManager(object _object)
            {
                ZonePairHorde = new Dictionary<uint, string>();
                ZonePairHorde.Add(207687, "Uldum");
                ZonePairHorde.Add(207686, "Twilight Highlands");
                ZonePairHorde.Add(207689, "Deepholm");
                ZonePairHorde.Add(207688, "Hyjal");
                ZonePairHorde.Add(206595, "Tol'Barad Peninsula");
                ZonePairHorde.Add(207690, "Vashj'ir");
                ZonePairHorde.Add(215424, "Pandaria");
                ZonePairAlly = new Dictionary<uint, string>();
                ZonePairAlly.Add(207692,"Hyjal");
                ZonePairAlly.Add(207693,"Deepholm");
                ZonePairAlly.Add(207694,"Twilight Highlands");
                ZonePairAlly.Add(207695,"Uldum");
                ZonePairAlly.Add(206594,"Tol'Barad Peninsula");
                ZonePairAlly.Add(207691, "Vashj'ir");
                ZonePairAlly.Add(215457, "Pandaria");
                ZoneIdDict = new Dictionary<uint, string>();
                ZoneIdDict.Add(5034, "Uldum");
                ZoneIdDict.Add(5144, "Vashj'ir");
                ZoneIdDict.Add(5145, "Vashj'ir");
                ZoneIdDict.Add(5146, "Vashj'ir");
                ZoneIdDict.Add(4815, "Vashj'ir");
                ZoneIdDict.Add(5042, "Deepholm");
                ZoneIdDict.Add(4922, "Twilight Highlands");
                ZoneIdDict.Add(616, "Hyjal");
                ZoneIdDict.Add(5389, "Tol'Barad Peninsula");
                PandariaMapId = 870;
           }
        }

        public List<string> NeedToMoveOutisde = new List<string> { "Twilight Highlands", "Vashj'ir"};
        public List<string> NeedToFlyBB = new List<string> { "Grind Bot", "Questing" };
        public List<string> NoProfileNeededBB = new List<string> { "BG Bot", "PvP", "ArchaeologyBuddy", "Instancebuddy" };
        public List<string> HearthCamper = new List<string> { "BG Bot", "PvP", "Instancebuddy", "Professionbuddy" };
        public List<int> BlackListedProfiles = new List<int>();
        #endregion

        #region Changer Thread
        private static Thread _ChangerThread;
        private static void ChangerThread(string _BotBase, string XMLFilepath,string ToDo)
        {
            if (ToDo == "Pause")
            {
                Thread.Sleep(20000);
                TreeRoot.Stop();
                BuddyManager.STATUS = "Short Break";
                while (TreeRoot.IsRunning) Thread.Sleep(500);
                Thread.Sleep(TimeSpan.FromMinutes(double.Parse(XMLFilepath)));
                if (!TreeRoot.IsRunning) TreeRoot.Start();
                BuddyManager.STATUS = "";
                Logging.Write("[BuddyManager] Short Break is complete.");
                _ChangerThread.Abort();
            }
            if (ToDo == "Pulse")
            {
                TreeRoot.Stop();
                while (TreeRoot.IsRunning) Thread.Sleep(500);
                Thread.Sleep(500);
                TreeRoot.Start();
                _ChangerThread.Abort();
            }
            if(ToDo == "Movement")
            {
                Logging.Write("[BuddyManager] Background thread starting \"Questing\".");
                if (TreeRoot.IsRunning)
                {
                    TreeRoot.Stop();
                    Thread.Sleep(1000);
                }
                foreach (KeyValuePair<string,BotBase> Base in BotManager.Instance.Bots)
                {
                    if (Base.Key.ToLower().Contains("questing"))
                    {
                        BotManager.Instance.SetCurrent(Base.Value);
                        if(!BotManager.Current.Initialized) BotManager.Current.Initialize();
                        Thread.Sleep(500);
                    }
                }
                ProfileManager.LoadEmpty();
                var FilePath = "";
                FilePath = String.Format("{0}/Plugins/BuddyManager/Profiles/Blank QO Apoc Int.xml", System.Windows.Forms.Application.StartupPath);
                ProfileManager.LoadNew(FilePath);
                Thread.Sleep(500);
                TreeRoot.Start();
                Logging.Write("[BuddyManager] Questing now running. Will proceed as needed.");
                _ChangerThread.Abort();
            }


            if(ToDo == "Restart")
            {
                Thread.Sleep(100);
                while(!StyxWoW.IsInGame || !StyxWoW.IsInWorld)
                {
                    Thread.Sleep(500);
                }
                Thread.Sleep(5000);
                while (!StyxWoW.IsInGame || !StyxWoW.IsInWorld)
                {
                    Thread.Sleep(500);
                }
                Thread.Sleep(2500);
                while (!StyxWoW.IsInGame || !StyxWoW.IsInWorld)
                {
                    Thread.Sleep(500);
                }
                Thread.Sleep(10000);
                //Logging.Write(System.Drawing.Color.Orange, "[BuddyManager] Background thread restarting TreeRoot.");
                TreeRoot.Stop();
                while(TreeRoot.IsRunning) Thread.Sleep(500);
                Thread.Sleep(500);
                TreeRoot.Start();
                _ChangerThread.Abort();
            }

            if (ToDo == "SubProfile")
            {
                Logging.Write(string.Format("[BuddyManager] Loading SubProfile: {0}", XMLFilepath));
                if (TreeRoot.IsRunning)
                { TreeRoot.Stop(); Thread.Sleep(1000); }
                ProfileManager.LoadEmpty();
                Thread.Sleep(500);
                ProfileManager.LoadNew(XMLFilepath);
                Thread.Sleep(2000);
                while (ProfileManager.CurrentOuterProfile.Equals(null) || ProfileManager.CurrentProfile.Equals(null)) { Thread.Sleep(500); }
                TreeRoot.Start();
                Logging.Write(string.Format("[BuddyManager] Restarted Bot with new SubProfile!"));
                _ChangerThread.Abort();

            }



            bool GotBotBase = false;
            Logging.Write("[BuddyManager] Background thread is working. Will restart HB in a few seconds.");
            if (TreeRoot.IsRunning)
            { TreeRoot.Stop(); Thread.Sleep(2000); }
            foreach (KeyValuePair<string, BotBase> Base in BotManager.Instance.Bots)
            {
                if (Base.Key.ToLower().Contains(_BotBase.ToLower()))
                {
                    BotManager.Instance.SetCurrent(Base.Value);
                    if (!BotManager.Current.Initialized) BotManager.Current.DoInitialize();
                    Thread.Sleep(500);
                    GotBotBase = true;
                }
            }
            if (!GotBotBase)
            {
                Logging.Write(string.Format("[BuddyManager] Couldn't load BotBase: {0}", _BotBase.ToString()));
                Logging.Write("[BuddyManager] Sending 'ForceQuit()' to Wow.exe");
                InactivityDetector.ForceLogout(true);
                _ChangerThread.Abort();
            }
            Thread.Sleep(500);
            ProfileManager.LoadEmpty();
            Thread.Sleep(500);
            if (XMLFilepath != "None")
            {
                ProfileManager.LoadNew(XMLFilepath);
                Thread.Sleep(3000);
            }
            while (ProfileManager.CurrentOuterProfile.Equals(null) || ProfileManager.CurrentProfile.Equals(null)) { Thread.Sleep(500); }
            TreeRoot.Start();
            Logging.Write(string.Format("[BuddyManager] Restarted Bot with Bot-Base: {0} and Profile FilePath: \"{1}\"", _BotBase.ToString(), XMLFilepath.ToString()));
            _ChangerThread.Abort();
        }
        #endregion

        #region StartChanger
        private void StartChanger()
        {
            MovementRunning = true;
            AfterHearth = false;
            SitAtHearth = false;
            IsNewZone = false;
            NeedToFly = false;
            NeedHearth = false;
            DidUseHearth = false;
            NeedToRepairMailSell = false;

            //If you happened to be BG Qued, get rid of that shit.
            if (Battlegrounds.GetQueuedBattlegroundInfo(1).EstimatedWaitTime != 0)
            {
                Log("Had BG Ques. Got rid of them.");
                Battlegrounds.AcceptBattlefieldPort(2, false);
                Battlegrounds.AcceptBattlefieldPort(1, false);
            }
            

            string XMLfilepath = TaskList[CurrentTaskIndex].ProfileList[CurrentProfileIndex];
            string botbase = TaskList[CurrentTaskIndex].BotBase;
            //Set these to local variables for ease of typing

            Log("Next Task Is As Follows!");
            TaskList[CurrentTaskIndex].ToLog();

            //if (uSettings.Mail || uSettings.Vendor) { NeedToRepairMailSell = true; Log("User has Mail/Sell/Repair Enabled."); }
            //else { NeedToRepairMailSell = false; Log("Mail/Sell/Repair all turned off."); }

            if (HearthCamper.Contains(botbase))
            { AfterHearth = true; NeedHearth = true; SitAtHearth = true; Log("Will be camping HearthStone upon restart."); }
            //Is a hearth camping bot-base (IB,BG,PvP)

            if (TaskList[CurrentTaskIndex].Zone != TaskList[LastTaskIndex].Zone) { AfterHearth = true; NeedHearth = true; IsNewZone = true; Log("Next Profile is set to run in :", TaskList[CurrentTaskIndex].Zone); }
            //If not on the first profile (since it would cause an exception)
            //Check if the zones are different, and if so, set it to switch zone

            if (TaskList[CurrentTaskIndex].Zone == "None") { NeedHearth = true; AfterHearth = true; }
            //If there is no zone set, use hearth!

            if (CurrentTaskIndex == 0 && TaskList[CurrentTaskIndex].Zone != "None") { NeedHearth = true; AfterHearth = true; IsNewZone = true; }
            //This is in case you start it somewherez else
            

            if (Me.ZoneId == 1637 && TaskList[CurrentTaskIndex].Zone != "None") { Log("Bot started in Orgrimmar, will use portal."); NeedHearth = false; AfterHearth = false; NeedToRepairMailSell = false; IsNewZone = true; }
            if (Me.ZoneId == 1519 && TaskList[CurrentTaskIndex].Zone != "None") { Log("Bot started in Stormwind, Will use portal."); NeedHearth = false; AfterHearth = false; NeedToRepairMailSell = false; IsNewZone = true; }
            //If bot started in main city, Will use respective portal and won't need to hearth, repair, or walk outside

            if (NeedToFlyBB.Contains(botbase))
            { NeedToFly = true; Log("Will be flying to first hotspot."); }
            //Grind bot and such will require flying to first hotspot

            if (LoadedFirst && TaskList[CurrentTaskIndex].Zone == TaskList[LastTaskIndex].Zone && !ForcedSRM && !HearthCamper.Contains(botbase))
            { NeedHearth = false; AfterHearth = false; NeedToRepairMailSell = false; IsNewZone = false; Log("This is not a switch for Repair/Vendor/Mail, and Zones are the same.  Staying in zone after switch."); }

            if (Me.ZoneId == 1637) { Log("In Orgrimmar already. No need to Hearth."); NeedHearth = false; AfterHearth = false; NeedToRepairMailSell = false; }
            if (Me.ZoneId == 1519) { Log("In Stormwind already. No need to Hearth."); NeedHearth = false; AfterHearth = false; NeedToRepairMailSell = false; }
            //For when we are on any but the first grouping.

            //if (ForcedSRM) { NeedHearth = true; AfterHearth = true; NeedToRepairMailSell = true; ForcedSRM = false; Log("This is a switch for Repair/Vendor/Mail.  Hearthing Mandatory!"); }
            //else { Log("Not a Forced Sell/Mail/Repair switch."); }

            LoadedFirst = true;
            DidJustRestart = true;
            Thread.Sleep(500);
            Thread.Sleep(500);
            Navigator.PlayerMover.MoveStop();
            StyxWoW.SleepForLagDuration();
            //_WaitingOnThread.Start();
            //_ChangerThread = new Thread(() => ChangerThread("", "", "Combat Bot"));
            //_ChangerThread.Start();
            MovementChanger();
            
            Thread.Sleep(2500);
            return;
        }
        #endregion


        public override void Pulse()
        {
            if (STATUS == "Short Break") return;
            if (!TimeToAlertTimer.IsRunning) TimeToAlertTimer.Start();
            if (TimeToAlertTimer.Elapsed.Minutes >= 15) { TotalBaseTime(); TimeToAlertTimer.Reset(); TimeToAlertTimer.Start(); }
            if (IsNotSafe()) return;
            /*if (System.Math.Round((DateTime.Now - _TotalStartTime).TotalMinutes) != 0 && Convert.ToInt32((DateTime.Now - _TotalStartTime).TotalMinutes) % 2 == 0)
            { Log(string.Format("Total time since originally started; Hours:{0} Mins:{1}", (DateTime.Now - _TotalStartTime).TotalHours.ToString(), (DateTime.Now - _TotalStartTime).TotalMinutes.ToString())); }
            if (System.Math.Round((DateTime.Now - _BaseStartTime).TotalMinutes) != 0 && Convert.ToInt32((DateTime.Now - _BaseStartTime).TotalMinutes) % 2 == 0)
            { Log(string.Format("Total time since Group {0} started; Hours:{1} Mins:{2}",CurrentTaskIndex.ToString(), (DateTime.Now - _BaseStartTime).TotalHours.ToString(), (DateTime.Now - _BaseStartTime).TotalMinutes.ToString())); }
            */
            if (!LoadedFirst)
            {
                bool inFirstZone = false;
                if (uSettings.Randomize)
                {
                    Log("Randomizing first task.");
                    CurrentTaskIndex = (RanNum(0, TaskList.Count - 1));
                    Log(string.Format("Chosen task: {0}", (CurrentTaskIndex)));
                }
                else
                {
                    CurrentTaskIndex = 0;
                    Log("Starting First Task!");
                }
                int indexIs = 0;
                for (int i = 0; i < TaskList.Count - 1; i++)
                {
                    if (TaskList[i].Zone != TaskList[CurrentTaskIndex].Zone)
                        indexIs = i;
                }
                LastTaskIndex = indexIs;
                foreach (KeyValuePair<uint, string> obj in _Manager.ZoneIdDict.Where(o => o.Value == TaskList[CurrentTaskIndex].Zone))
                {
                    if (obj.Key == Me.ZoneId) inFirstZone = true;
                }

                if (TaskList[CurrentTaskIndex].Zone == "Pandaria" && Me.MapId == _Manager.PandariaMapId)
                    inFirstZone = true;

                if (inFirstZone)
                {
                    Log("You have chosen to start the bot in the first zone.");
                    Log("First Task Is As Follows:");
                    TaskList[CurrentTaskIndex].ToLog();
                    LoadedFirst = true;
                    LoadChanger();
                    return;
                }
                /*if (!BotManager.Current.Name.Contains(_Manager.BotBase) || _Manager.FilePath[CurrentTaskIndex].Contains(Styx.Logic.Profiles.ProfileManager.XmlLocation))*/
                StartChanger();
            }


            if (!uSettings.LogOutAfter && !IsNotSafe() && ((DateTime.Now - _TotalStartTime).TotalMinutes >= ((uSettings.TotalHr * 60) + uSettings.TotalMin)))
            {
                TotalRunningTime();
                Log("Total Time to loop has been reached. Sending 'ForceQuit()' to WoW.");
                InactivityDetector.ForceLogout(true);
                TreeRoot.Stop();
            }
            if (EXITNOW) { TotalRunningTime(); Log("ExitNow set to true. Sending 'ForceQuit()' to WoW."); InactivityDetector.ForceLogout(true); TreeRoot.Stop(); }


            #region NeedHearth
            if (NeedHearth)
            {
                Stopwatch HearthTimer = new Stopwatch();
                bool HasHeartStone = false;
                ObjectManager.Update();
                WoWItem stone;
                SpellManager.StopCasting();
                if (Me.IsFlying && !Me.IsSwimming)
                {
                    var landingTimer = new Stopwatch();
                    landingTimer.Start();
                    Log("Landing.");
                    StyxWoW.SleepForLagDuration();
                    while (Me.IsFlying && !Me.IsSwimming) { WoWMovement.Move(WoWMovement.MovementDirection.Descend); if (Me.IsSwimming || landingTimer.ElapsedMilliseconds >= 10000 || Me.IsJustAboveWater()) { Log("Hit Water, or took over 10 seconds."); break; } }
                    StyxWoW.SleepForLagDuration();
                    WoWMovement.MoveStop(WoWMovement.MovementDirection.Descend);
                    WoWMovement.MoveStop(WoWMovement.MovementDirection.All);
                    WoWMovement.MoveStop();
                    Log("Landed.");
                }
                Mount.Dismount();
                if (Me.HasAura("Swift Flight Form"))
                {
                    Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/cancelaura Swift Flight Form"));
                }
                if (Me.HasAura("Flight Form"))
                {
                    Lua.DoString(string.Format("RunMacroText(\"{0}\")", "/cancelaura Flight Form"));
                }
                Styx.Pathing.Flightor.MountHelper.Dismount();
                Navigator.PlayerMover.MoveStop();
                StyxWoW.SleepForLagDuration();
                Thread.Sleep(500);
                /*if (Me.Class == WoWClass.Mage)
                {
                    SpellManager.StopCasting();
                    Styx.Logic.Mount.Dismount();
                    Navigator.PlayerMover.MoveStop();
                    StyxWoW.SleepForLagDuration();
                    if (SpellManager.CanCast(3567))
                    {
                        SpellManager.Cast(3567);
                        Thread.Sleep(2500);
                        while (Me.IsCasting || !StyxWoW.IsInWorld)
                        {
                            Log("Sleeping while casting", null);
                            Thread.Sleep(5000);
                        }
                        Log("End of Sleep 1, Sleep additional 5 seconds.", null);
                        Thread.Sleep(5000);
                    }
                }
                else
                {*/
                Log("Looking for Hearthstone!.");
                foreach (WoWItem _item in ObjectManager.GetObjectsOfType<WoWItem>().Where(o => o.BagSlot != -1 && o.Entry == 6948))
                {
                    HasHeartStone = true;
                    Log("Has a Stone.");
                    if (_item.Cooldown < 1)
                    {
                        Log("Not on cooldown!");
                        DidUseHearth = true;
                        stone = _item;
                        Thread.Sleep(1000);
                        _item.Use();
                        HearthTimer.Start();
                        Thread.Sleep(2000);
                        while (Me.IsCasting) { Log("Sleep while Casting."); Thread.Sleep(100); }
                        Thread.Sleep(500);
                        if (HearthTimer.Elapsed.Seconds >= 9.9) { HearthTimer.Reset(); NeedHearth = false; Log("Hearthstone worked!"); }
                        else { HearthTimer.Reset(); NeedHearth = true; Log("Something Interrupted Hearthstone!"); return; }
                    }
                    else
                    {
                        NeedHearth = false;
                        Log("Your hearthstone was on cooldown.  Attempting to run anyways!");
                        AfterHearth = false;
                        IsNewZone = false;
                        DidUsePortal = false;
                        MovementRunning = true;
                        return;

                    }
                }
                if (!HasHeartStone) { Log("You don't have a HearthStone in bags. GO GET ONE!  ExitNow!"); EXITNOW = true; return; }
                AfterHearth = true;
                ResetChanger();
                return;
            }
            #endregion


            #region AfterHearth
            if (AfterHearth && !NeedHearth)
            {
                while (!StyxWoW.IsInGame || !StyxWoW.IsInWorld) Thread.Sleep(1000);
                var Outside = new WoWPoint(0, 0, 0);
                Log("Sleepy for 5 seconds. At Home City.");

                Thread.Sleep(5000);

                ObjectManager.Update();

                if (uSettings.shortBreak)
                    PauseChanger();

                foreach (WoWUnit iKeeper in ObjectManager.GetObjectsOfType<WoWUnit>().Where(o => (o.Entry == 6929 || o.Entry == 46642 || o.Entry == 44235 || o.Entry == 6740 || o.Entry == 44785) && o.Location.Distance(Me.Location) < 30))
                {
                    var r = RanNum(1, 5);
                    //Implementation of randomized "outside" points
                    if (iKeeper.Entry == 6929)
                    {
                        Log("Hearth set to Valley of Strength (Gryshka).");
                        if (r == 1) Outside = new WoWPoint(1586.992, -4419.707, 15.01287);
                        if (r == 2) Outside = new WoWPoint(1576.276, -4406.492, 15.54875);
                        if (r == 3) Outside = new WoWPoint(1560.885, -4401.947, 16.97374);
                        if (r == 4) Outside = new WoWPoint(1543.594, -4401.243, 18.33098);
                        if (r == 5) Outside = new WoWPoint(1560.066, -4390.32, 16.83468);
                    }
                    if (iKeeper.Entry == 46642)
                    {
                        Log("Hearth set to Valley of Honor (Nufa).");
                        if (r == 1) Outside = new WoWPoint(1935.14, -4696.542, 35.96473);
                        if (r == 2) Outside = new WoWPoint(1936.458, -4720.139, 37.03839);
                        if (r == 3) Outside = new WoWPoint(1941.931, -4707.184, 36.74498);
                        if (r == 4) Outside = new WoWPoint(1916.914, -4700.43, 35.84605);
                        if (r == 5) Outside = new WoWPoint(1963.691, -4670.242, 33.12001);
                    }
                    if (iKeeper.Entry == 44785)
                    {
                        Log("Hearth set to Valley of Wisdom (Miwana).");
                        if (r == 1) Outside = new WoWPoint(1926.933, -4195.518, 36.89679);
                        if (r == 2) Outside = new WoWPoint(1919.178, -4217.189, 36.75275);
                        if (r == 3) Outside = new WoWPoint(1929.971, -4227.032, 36.65667);
                        if (r == 4) Outside = new WoWPoint(1938.301, -4246.174, 32.84073);
                        if (r == 5) Outside = new WoWPoint(1945.244, -4246.469, 32.77121);
                    }
                    if (iKeeper.Entry == 44235)
                    {
                        Log("Hearth set to Dwarven district (Thaegra).");
                        if (r == 1) Outside = new WoWPoint(-8380.801, 618.5749, 95.62397);
                        if (r == 2) Outside = new WoWPoint(-8387.216, 615.63, 95.30541);
                        if (r == 3) Outside = new WoWPoint(-8395.315, 624.5509, 95.32862);
                        if (r == 4) Outside = new WoWPoint(-8379.59, 637.8062, 94.88734);
                        if (r == 5) Outside = new WoWPoint(-8348.097, 640.3146, 95.32527);
                    }
                    if (iKeeper.Entry == 6740)
                    {
                        Log("Hearth set to Trade district (Allison).");
                        if (r == 1) Outside = new WoWPoint(-8853.698, 656.3289, 96.68601);
                        if (r == 2) Outside = new WoWPoint(-8850.2, 662.5043, 97.34945);
                        if (r == 3) Outside = new WoWPoint(-8851.102, 652.3545, 96.62885);
                        if (r == 4) Outside = new WoWPoint(-8844.244, 637.6185, 95.71284);
                        if (r == 5) Outside = new WoWPoint(-8868.864, 642.7043, 96.04487);
                    }

                    break;
                }
                if (Outside != new WoWPoint(0, 0, 0))
                {
                    Log("Moving Outside to prevent flying stucks.");
                    while (Outside.Distance(Me.Location) >= 3) { Navigator.MoveTo(Outside); }
                }
                else
                    Log("Not currently a supported Innkeeper.  Please reply in the BuddyManager thread on the forums to have it added.");
                AfterHearth = false;
                PulseChanger();
                return;
            }
            #endregion

            if (!NeedHearth && !AfterHearth && NeedToRepairMailSell)
            { RepairSellMail(uSettings.Vendor, uSettings.Mail); return; }

            #region IsNewZone
            if (!SitAtHearth && !NeedHearth && !AfterHearth && !NeedToRepairMailSell && IsNewZone)
            {
                var v = RanNum(1, 5);
                WoWPoint PortalsHorde = new WoWPoint(2055.473, -4378.082, 98.84528);//
                WoWPoint PortalsAlly = new WoWPoint(-8209.668, 428.5376, 118.0617);//
                
                if (v == 2)
                {
                    PortalsHorde = new WoWPoint(2055.771, -4386.66, 99.00553);//
                    PortalsAlly = new WoWPoint(-8231.248, 429.3691, 118.2596);//
                }
                if (v == 3)
                {
                    PortalsHorde = new WoWPoint(2038.422, -4379.706, 99.09998);//
                    PortalsAlly = new WoWPoint(-8208.059, 414.3687, 117.6626);//
                }
                if (v == 4)
                {
                    PortalsHorde = new WoWPoint(2047.019, -4366.154, 98.97168);//
                    PortalsAlly = new WoWPoint(-8197.056, 429.8963, 117.7466);//
                }
                if (v == 5)
                {
                    PortalsHorde = new WoWPoint(2020.684, -4367.965, 97.81767);//
                    PortalsAlly = new WoWPoint(-8208.76, 418.5132, 118.1734);//
                }

                if (TaskList[CurrentTaskIndex].Zone == "Pandaria")
                {
                    PortalsHorde = new WoWPoint(2012.694, -4699.657, 28.62985);
                    PortalsAlly = new WoWPoint(-8195.631, 530.0829, 117.4178);
                }

                if (Me.IsHorde)
                {
                    //if (RepairAtHearth) { } //Embedded if sell at hearth
                    //if (MailAtHearth) { }

                    ObjectManager.Update();
                    while (PortalsHorde.Distance(Me.Location) > 5)
                    {
                        if (!Flightor.MountHelper.Mounted && Flightor.MountHelper.CanMount)
                        {
                            Flightor.MountHelper.MountUp();
                            StyxWoW.SleepForLagDuration();
                            Thread.Sleep(500);
                            while (Me.IsCasting) { Thread.Sleep(100); }
                        }
                        Log("Mounted and flying to Portal(s)!");
                        Flightor.MoveTo(PortalsHorde);
                        Thread.Sleep(250);
                    }
                    Log("Dismounting.");
                    WoWMovement.Move(WoWMovement.MovementDirection.Descend, TimeSpan.FromSeconds(2));
                    Flightor.MountHelper.Dismount();
                    StyxWoW.SleepForLagDuration();
                    WoWMovement.MoveStop(WoWMovement.MovementDirection.All);
                    Navigator.PlayerMover.MoveStop();
                    Log("Sleep a little bit at portals.");
                    Thread.Sleep(1000);
                    ObjectManager.Update();
                    uint Portal = 0;
                    foreach (KeyValuePair<uint, string> check in _Manager.ZonePairHorde)
                    {
                        if (check.Value.ToLower() == TaskList[CurrentTaskIndex].Zone.ToLower()) { Portal = check.Key; Log("Portal Id is: ", check.Key.ToString()); }
                    }
                    foreach (WoWGameObject _portal in ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.Entry == Portal))
                    {
                        while (_portal.Location.Distance(Me.Location) > _portal.InteractRange)
                        {
                            Navigator.MoveTo(_portal.Location);
                            Log(string.Format("Moving towards: {0}.", _portal.Name));
                            Thread.Sleep(100);
                        }
                        Navigator.PlayerMover.MoveStop();
                        WoWMovement.MoveStop(WoWMovement.MovementDirection.All);
                        WoWMovement.MoveStop();
                        Thread.Sleep(RanNum(500, 2000));
                        _portal.Interact();
                        IsNewZone = false;
                    }
                }


                if (Me.IsAlliance)
                {
                    ObjectManager.Update();
                    while (PortalsAlly.Distance(Me.Location) > 5)
                    {
                        if (!Flightor.MountHelper.Mounted && Flightor.MountHelper.CanMount)
                        {
                            Flightor.MountHelper.MountUp();
                            StyxWoW.SleepForLagDuration();
                            Thread.Sleep(500);
                            while (Me.IsCasting) { Thread.Sleep(100); }
                        }
                        Log("Mounted and flying to Storm Portals!");
                        Flightor.MoveTo(PortalsAlly);
                        Thread.Sleep(250);
                    }
                    Log("Dismounting.");
                    Flightor.MountHelper.Dismount();
                    StyxWoW.SleepForLagDuration();
                    WoWMovement.MoveStop(WoWMovement.MovementDirection.All);
                    Navigator.PlayerMover.MoveStop();


                    Log("Sleep a little bit at portals.");
                    Thread.Sleep(1000);

                    ObjectManager.Update();
                    uint Portal = 0;
                    foreach (KeyValuePair<uint, string> check in _Manager.ZonePairAlly)
                    {
                        if (check.Value.ToLower() == TaskList[CurrentTaskIndex].Zone.ToLower()) { Portal = check.Key; Log("Portal Id is: ", check.Key.ToString()); }
                    }
                    foreach (WoWGameObject _portal in ObjectManager.GetObjectsOfType<WoWGameObject>().Where(o => o.Entry == Portal))
                    {
                        while (_portal.Location.Distance(Me.Location) > _portal.InteractRange)
                        {
                            Navigator.MoveTo(_portal.Location);
                            Log(string.Format("Moving towards: {0}.", _portal.Name));
                            Thread.Sleep(100);
                        }
                        Navigator.PlayerMover.MoveStop();
                        WoWMovement.MoveStop(WoWMovement.MovementDirection.All);
                        WoWMovement.MoveStop();
                        Thread.Sleep(RanNum(500, 2000));
                        _portal.Interact();
                        IsNewZone = false;
                    }
                }
                if (IsNewZone) { Log("Failed to find the portal.  This will cause HB to endlessly loop. Will instead ExitNow."); EXITNOW = true; return; }
                else Log("Sent your toon through the portal to :", TaskList[CurrentTaskIndex].Zone);
                DidUsePortal = true;
                ResetChanger();
                return;

            }
            #endregion

            if (DidUsePortal)
            {
                MoveAfterPortal();
            }

            if (MovementRunning)
            {
                LoadChanger();
            }

            #region NeedToFly
            if (NeedToFly && !NeedHearth && !IsNewZone && !SitAtHearth)
            {
                //If I don't have flying in Pandaria, then no reason to try to fly there.
                if (TaskList[CurrentTaskIndex].Zone == "Pandaria" && !SpellManager.HasSpell(115913))
                {
                    NeedToFly = false;
                    return;
                }

                Log("Sleepy for 5 seconds.");
                Thread.Sleep(5000);
                //Need a returnBool from Lua IsFlyableArea()
                ObjectManager.Update();
                if (TaskList[CurrentTaskIndex].BotBase == "Grind Bot")
                {
                    Log("BotBase is 'Grind Bot'.  Flying started.");
                    //StopWatch GrindTimer = new StopWatch();
                    //GrindTimer.Start()
                    ProfileManager.CurrentProfile.GrindArea.GetNextHotspot();
                    Hotspot hotspot = ProfileManager.CurrentProfile.GrindArea.CurrentHotSpot;
                    while (hotspot.Position.Distance(Me.Location) > 5 && !IsNotSafe())
                    {
                        if (!Flightor.MountHelper.Mounted && Flightor.MountHelper.CanMount)
                        {
                            Flightor.MountHelper.MountUp();
                            StyxWoW.SleepForLagDuration();
                            Thread.Sleep(250);
                            while (Me.IsCasting) { Thread.Sleep(100); }
                        }
                        Log("Mounted and flying to HotSpot!");
                        Flightor.MoveTo(hotspot.Position);
                        Thread.Sleep(100);
                        //if (GrindTimer.Elapsed.Minutes > 5) { Log("Took over 5 minutes to attempt flying to first hotspot.\nBreaking while loop."); whileTimer.Reset(); break; }
                    }
                    if (hotspot.Position.Distance(Me.Location) <= 30)
                    {
                        Log("Landing.");
                        Navigator.PlayerMover.MoveStop();
                        StyxWoW.SleepForLagDuration();
                        WoWMovement.Move(WoWMovement.MovementDirection.Descend, TimeSpan.FromSeconds(1));
                        WoWMovement.MoveStop();
                        Flightor.MountHelper.Dismount();
                        Navigator.Clear();
                        Log("Landed at HotSpot. Thread released.");
                        NeedToFly = false;
                    }
                }

                //Questing is not currently supported.  Lot of shit to look at with this.
                if (TaskList[CurrentTaskIndex].BotBase == "Questing")
                {

                    Stopwatch QuestTimer = new Stopwatch();
                    if (!QuestTimer.IsRunning) { QuestTimer.Start(); return; }
                    QuestTimer.Reset();
                    WoWPoint POI_ = BotPoi.Current.Location;
                    while (POI_.Distance(Me.Location) > 30 && !IsNotSafe())
                    {
                        if (!Flightor.MountHelper.Mounted && Flightor.MountHelper.CanMount)
                        {
                            Flightor.MountHelper.MountUp();
                            StyxWoW.SleepForLagDuration();
                            Thread.Sleep(250);
                            while (Me.IsCasting) { Thread.Sleep(100); }
                        }
                        Log("Mounted and flying to first POI!");
                        Flightor.MoveTo(POI_);
                        Thread.Sleep(100);
                        //if (whileTimer.Elapsed.Minutes > 5) { Log("Took over 5 minutes to attempt flying to first hotspot.\nBreaking while loop."); whileTimer.Reset(); break; }
                    }
                    if (POI_.Distance(Me.Location) <= 30)
                    {
                        Log("Landing.");
                        Navigator.PlayerMover.MoveStop();
                        StyxWoW.SleepForLagDuration();
                        while (Me.IsFlying) { WoWMovement.Move(WoWMovement.MovementDirection.Descend, TimeSpan.FromSeconds(1)); }
                        WoWMovement.MoveStop();
                        Log("Landed at POI. Thread released.");
                        NeedToFly = false;
                    }
                }
                NeedToFly = false;
            }
            #endregion

            if (!NeedToFly && DidJustRestart) 
            {
                if (!GB2_StoredSettings && TaskList[CurrentTaskIndex].BotBase == "Gatherbuddy2" && Me.Location.Distance(HotspotManager.CurrentHotSpot) > 30)
                {
                    harvestHerbs = Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherHerbs;
                    harvestOres = Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherMinerals;
                    Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherMinerals = false;
                    Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherHerbs = false;
                    GB2_StoredSettings = true;
                    Log("Turned off gathering in GB2 while flying to profile area.");
                    return;
                }
                if (GB2_StoredSettings && Me.Location.Distance(Bots.Gatherbuddy.Profile.CurrentProfile.Current) < 50)
                {
                    Log("At profile area - Restoring GB2 gathering settings.");
                    Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherHerbs = harvestHerbs;
                    Bots.Gatherbuddy.GatherbuddySettings.Instance.GatherMinerals = harvestOres;
                    GB2_StoredSettings = false;
                    Log("We're done here for now.  Awaiting something to do :) "); DidJustRestart = false;
                }
            }


            #region Full Task Switching!
            // FULL TASK SWITCHING
            // *******************
            if (TaskList[CurrentTaskIndex].SwitchOn == "Nodes" && (_InternalNodeCount + GB2FullNodesCollection() >= TaskList[CurrentTaskIndex].SwitchInt))
            {
                SwitchTaskChecksUpdates();
                StartChanger();
            }

            if (TaskList[CurrentTaskIndex].SwitchOn == "Minutes" && (DateTime.Now - _BaseStartTime).TotalMinutes >= TaskList[CurrentTaskIndex].SwitchInt)
            {
                SwitchTaskChecksUpdates();
                StartChanger();
            }

            if (!IsLastProfile() && ((BotManager.Current.Name == "Gatherbuddy2" || BotManager.Current.Name == "Grind Bot") && TaskList[CurrentTaskIndex].ProfileList.Count > 1))
            {
                if (
                    (((DateTime.Now - _BaseStartTime).TotalMinutes / Convert.ToDouble(TaskList[CurrentTaskIndex].SwitchInt) >= ((Convert.ToDouble(CurrentProfileIndex) + 1) / (Convert.ToDouble(TaskList[CurrentTaskIndex].ProfileList.Count)))) && TaskList[CurrentTaskIndex].SwitchOn == "Minutes")
                    ||
                    ((Convert.ToDouble(_InternalNodeCount + GB2FullNodesCollection()) / Convert.ToDouble(TaskList[CurrentTaskIndex].SwitchInt) >= ((Convert.ToDouble(CurrentProfileIndex) + 1) / (Convert.ToDouble(TaskList[CurrentTaskIndex].ProfileList.Count)))) && TaskList[CurrentTaskIndex].SwitchOn == "Nodes")
                    )
                {

                    Log("Sub-Profile Changing!");
                    CurrentProfileIndex++;
                    SwappingToNewProfileSkipStartupResets = true;
                    SwapProfileChanger(CurrentProfileIndex);
                }
            }

            #endregion


            if (ItemCheck(6948) != null && ItemCheck(6948).Cooldown >= 5)
            { return; }

            #region ForceNext Vendor/Mail
            if (uSettings.ForceNext && (((Me.BagsFull || Me.FreeBagSlots <= (ProfileManager.CurrentProfile.MinFreeBagSlots + 1)) && uSettings.Vendor) || (BotPoi.Current.Type == PoiType.Mail && uSettings.Mail) || (BotPoi.Current.Type == PoiType.Sell && uSettings.Vendor) || (BotPoi.Current.Type == PoiType.Repair && uSettings.Vendor)))
            {
                uSettings.TasksCompleted++;
                LastTaskIndex = CurrentTaskIndex;
                if (uSettings.Randomize)
                {
                    Log("Randomizing next task.");
                    while (CurrentTaskIndex == LastTaskIndex)
                    {
                        CurrentTaskIndex = (RanNum(0, TaskList.Count - 1));
                    }
                    Log(string.Format("Chosen task: {0}", (CurrentTaskIndex)));
                }
                else
                    CurrentTaskIndex++;
                Log("Found HB needs to Mail/Sell/Repair.");
                ForcedSRM = true;
                Log(string.Format("Task {0} completed", LastTaskIndex.ToString()));
                TotalRunningTime();

                if (WasLastTask(_BaseStartTime, LastTaskIndex))
                {
                    Log("All tasks have been completed, and BM is not set to loop.");
                    Log("Sending ForceQuit() to Wow.exe");
                    InactivityDetector.ForceLogout(true);
                    return;
                }
                if (!uSettings.Randomize && CurrentTaskIndex >= TaskList.Count - 1) CurrentTaskIndex = 0;

                StartChanger();
            }
            #endregion
        }

        private int GB2FullNodesCollection()
        {
            int tmpInt = 0;
            foreach (var x in Bots.Gatherbuddy.GatherbuddyBot.NodeCollectionCount)
            {
                tmpInt += x.Value;
            }
            return tmpInt;
        }

        private void ResetChanger()
        {
            Thread.Sleep(5000);
            return;
            /*Thread.Sleep(500);
            _ChangerThread = new Thread(() => ChangerThread(_Manager.BotBase, _Manager.FilePath[CurrentTaskIndex], "Restart"));
            _ChangerThread.Start();
            Thread.Sleep(15000);
            return;*/
        }

        private void MovementChanger()
        {
            Thread.Sleep(5000);
            _ChangerThread = new Thread(() => ChangerThread(TaskList[CurrentTaskIndex].BotBase,TaskList[CurrentTaskIndex].ProfileList[CurrentProfileIndex], "Movement"));
            _ChangerThread.Start();
            Thread.Sleep(15000);
            return;
        }

        private void PulseChanger()
        {
            Thread.Sleep(2500);
            return;
            /*_ChangerThread = new Thread(() => ChangerThread(_Manager.BotBase, _Manager.FilePath[CurrentTaskIndex], "Pulse"));
            _ChangerThread.Start();
            Thread.Sleep(15000);
            return;*/
        }

        private void PauseChanger()
        {
            if (RanNum(1, 4) != 4)
            {
                var x = RanNum(5, 10);
                Log(String.Format("Taking a short break for {0} Minutes", x.ToString()));
                _ChangerThread = new Thread(() => ChangerThread("", x.ToString(), "Pause"));
                Thread.Sleep(10000);
            }
            else
                Log("Skipping the short break.  25% chance of this happening.");
        }

        private void LoadChanger()
        {
            MovementRunning = false;
            DidJustRestart = true;
            Thread.Sleep(500);
            Navigator.PlayerMover.MoveStop();
            StyxWoW.SleepForLagDuration();
            //_WaitingOnThread.Start();
            _ChangerThread = new Thread(() => ChangerThread(TaskList[CurrentTaskIndex].BotBase,TaskList[CurrentTaskIndex].ProfileList[CurrentProfileIndex],"Load"));
            _ChangerThread.Start();
            Thread.Sleep(15000);
        }

        private void SwapProfileChanger(int ProfileIndex)
        {
            DidJustRestart = true;
            Thread.Sleep(500);
            if (TaskList[CurrentTaskIndex].BotBase == "Grind Bot")
                NeedToFly = true;
            Thread.Sleep(500);
            _ChangerThread = new Thread(() => ChangerThread(TaskList[CurrentTaskIndex].BotBase, TaskList[CurrentTaskIndex].ProfileList[ProfileIndex], "SubProfile"));
            _ChangerThread.Start();
            Thread.Sleep(15000);
        }
    }
}


